/*
 * Building.cpp
 *
 *  Created on: 25.1.2013
 *      Author: Travis
 */

#ifdef _WIN32 
#include <windows.h> 
#endif

#include "Building.h"
#include "../../../special/StrIntConvert.h"
#include "../../dynamic/villager/Villager.h"

Building::Building(glm::vec3 _Pos, float _r, std::string _Name,
		std::string _modelFName, ModelPool *_mPool, PathFinder *_pathfinder) :
		staticEntity(_Pos, _r, _Name, _modelFName, _mPool, _pathfinder)
{
	type = OBJ_BUILDING;
	parentType = OBJ_STATIC;

	constructionMark = mPool->loadModel("underConstruction", "");

	// override default shader id
	shaderID = Shader::sPool->getProgramID("building");
	shadowShaderID = Shader::sPool->getProgramID("building_sh");
	virtualShaderID = Shader::sPool->getProgramID("building_virtual");

	age = 100;
	money = 0;

	cost = 200;

	// default activity radius
	activityRadius = 25;

	// set defaul maximum count of units
	MaxSlaves = START_MAX_SLAVES;

	BuildUnitBar(modelFName + "_char.png");

	gPoint = glm::vec2(Pos.x, Pos.z);
	gPoint.x = gPoint.x - (getBBox()->GetDiagonalOfBase() / 2);
}

Building::~Building()
{
}

void Building::insertSlave(Entity* slave)
{
	if (slave == NULL)
		return;

	// only villager's children
	if (slave->getParentType() != OBJ_VILLAGER)
		return;

	// retype slave to villager
	Villager *villager = static_cast<Villager*>(slave);

	if (slaves.size() < MaxSlaves)
	{
		slaves.push_back(villager);

		// set this building ownter of villager
		villager->setOwner(this);

		// update info label
		infoLabel->setCaption(
				"Workers: " + convertInt(slaves.size()) + "/" + convertInt(MaxSlaves));
	}
}

bool Building::enoughSpace()
{
	if (slaves.size() < MaxSlaves)
		return true;
	else
		return false;
}

void Building::BuildUnitBar(std::string iconFName)
{
	// main form holding other info and butons
	unitBar = new Gadgets::Form(800, 64);
	unitBar->setPos(glm::vec2(0, 0));

	icon = new Gadgets::Form(64, 64);
	icon->setBackground(iconFName);
	icon->setPos(glm::vec2(5, 0));

	nameLabel = new Gadgets::Label(64, 16);
	nameLabel->setPos(glm::vec2(75, 8));
	nameLabel->setCaption(Name);

	infoLabel = new Gadgets::Label(64, 16);
	infoLabel->setPos(glm::vec2(75, 24));

	addWorkerButton = new Gadgets::Button(32, 32);
	addWorkerButton->setVisible(false);
	addWorkerButton->setUserData2(this); // SET DATA2 OF EVENT
	addWorkerButton->setPos(glm::vec2(750, 16));
	addWorkerButton->setBackground("addWorkerButton.png");

	unitBar->addItem(icon);
	unitBar->addItem(nameLabel);
	unitBar->addItem(infoLabel);
	unitBar->addItem(addWorkerButton);
}

void Building::updateAge()
{
	if (age < MAX_AGE)
	{
		if (age > 0.0)
			status = STATUS_UNDER_CONSTRUCTION;

		infoLabel->setCaption(
				"Under construction " + convertInt((int) age) + "/" + "100");
	}
	else
	{
		underConstruction = false;
		status = STATUS_READY;

		infoLabel->setCaption(
				"Workers: " + convertInt(slaves.size()) + "/" + convertInt(MaxSlaves));
		addWorkerButton->setVisible(true);
	}
}

void Building::control(float t)
{
	// exit when unit is sleeping
	if (sleeping)
		return;

	updateAge();
}

void Building::goTo(glm::vec2 pos)
{
}

void Building::draw(int shadertype)
{

	// exit when unit is sleeping
	if (sleeping)
		return;

	// increase counter (for counting visible objects)
	World::counter += 1;

	// using normal shader for object
	if ((shadertype == SHADER_NORMAL) || (shadertype == SHADER_REFLECTION)
			|| (shadertype == SHADER_VIRTUAL))
	{
		// get matrix
		glm::mat4 ModelMatrix;

		if (status == STATUS_PLACED)
			ModelMatrix = glm::mat4(1.0);
		else
			ModelMatrix = glm::scale(glm::mat4(1.0f),
					glm::vec3(1.0, age / 100.0, 1.0));

		glm::mat4 ViewMatrix = glm::translate(World::world->getView(),
				glm::vec3(Pos.x, Pos.y, Pos.z));
		ViewMatrix = glm::rotate(ViewMatrix, r, glm::vec3(0.0f, 1.0f, 0.0f));
		glm::mat4 MVP = World::world->getProjection() * ViewMatrix * ModelMatrix;

		// get light information
		glm::vec3 LightPos = World::world->getLightPos(); // position of light
		glm::vec3 LightDif = World::world->getLightDif(); // diffuse color of light
		glm::vec3 LightAmb = World::world->getLightAmb(); // ambient color of light
		glm::vec3 LightSpec = World::world->getLightSpe(); // specular color of light

		// start shader program
		if (shadertype != SHADER_VIRTUAL)
		{
			glUseProgram(shaderID);
		}
		else
		{
			glUseProgram(virtualShaderID);
			glEnable(GL_BLEND);
		}
		// send matrix to shader
		glUniformMatrix4fv(glGetUniformLocation(shaderID, "MVP"), 1, GL_FALSE,
				&MVP[0][0]);
		glUniformMatrix4fv(glGetUniformLocation(shaderID, "M"), 1, GL_FALSE,
				&ModelMatrix[0][0]);
		glUniformMatrix4fv(glGetUniformLocation(shaderID, "V"), 1, GL_FALSE,
				&ViewMatrix[0][0]);
		glUniform3f(glGetUniformLocation(shaderID, "LightPosition_worldspace"),
				LightPos.x, LightPos.y, LightPos.z);
		glUniform3f(glGetUniformLocation(shaderID, "lightAmb"), LightAmb.x,
				LightAmb.y, LightAmb.z);
		glUniform3f(glGetUniformLocation(shaderID, "lightDif"), LightDif.x,
				LightDif.y, LightDif.z);
		glUniform3f(glGetUniformLocation(shaderID, "lightSpec"), LightSpec.x,
				LightSpec.y, LightSpec.z);

		glUniform1i(glGetUniformLocation(shaderID, "tex0"), 0);

		// draw model
		if (status == STATUS_PLACED)
			mPool->drawModelByID(constructionMark);
		else
			mPool->drawModelByID(modelID[0]);

		glUseProgram(0);

		if (shadertype == SHADER_VIRTUAL)
			glDisable(GL_BLEND);

		drawMarker(4.0); // draw marker
	}
	// using shader for shadows
	else if (shadertype == SHADER_SHADOW)
	{
		glm::mat4 ModelMatrix;

		// get shadow matrix
		if (status == STATUS_PLACED)
			ModelMatrix = glm::mat4(1.0);
		else
			ModelMatrix = glm::scale(glm::mat4(1.0f),
					glm::vec3(1.0, age / 100.0, 1.0));

		glm::mat4 ViewMatrix = glm::translate(World::world->getShadowView(),
				glm::vec3(Pos.x, Pos.y, Pos.z));
		ViewMatrix = glm::rotate(ViewMatrix, r, glm::vec3(0.0f, 1.0f, 0.0f));
		glm::mat4 MVP = World::world->getShadowProjection() * ViewMatrix
				* ModelMatrix;

		glUseProgram(shadowShaderID);

		// send matrix to shader
		glUniformMatrix4fv(glGetUniformLocation(shadowShaderID, "depthMVP"), 1,
				GL_FALSE, &MVP[0][0]);

		glUniform1i(glGetUniformLocation(shadowShaderID, "tex0"), 0);

		// draw model
		if (status == STATUS_PLACED)
			mPool->drawModelByID(constructionMark);
		else
			mPool->drawModelByID(modelID[0]);

		glUseProgram(0);

	}

}

int Building::getMaxSlaves()
{
	return MaxSlaves;
}

int Building::getCountOfSlaves()
{
	return slaves.size();
}

Gadgets::Button* Building::getAddWorkerButton()
{
	return addWorkerButton;
}

glm::vec2 Building::getGPoint()
{
	return gPoint;
}

int Building::getMoney()
{
	int m = money;
	money = 0;
	return m;
}

void Building::incMoney(int money)
{
	this->money += money;
}
